/***********************************************************************************
 * 文件名： soft_uart.c
 * 版本： 3
 * 说明：
 * 		软件模拟UART。提供单个字节发送和接收的基本功能，类似于常见MCU的基础UART外设。
 *      通过定时器中断中调用 SUart_EvTimer 来定时查询IO状态进行接收，定时控制IO状态进行发送。
 *      在头文件中查看其它 API 以及说明。
 * 修改记录：
 * 	2021/04/28: 初版。 刘言。
 *  2022/06/06: 新增同步模式；新增 _SUART_INIT_STATE 配置项。
 *  2022/12/30: 可以同++替代的赋值语句全部用++替代，降低ROM占用
 ***********************************************************************************/
#include "soft_uart.h"
#include "..\..\polsys.h"

#ifndef _SUART_USE_SYNC_MODE
bit _SUart_Run = false;
static u8 SUart_mRxStep = _SUART_INIT_STATE; // 接收步骤
static u8 SUart_mRxCycCount; // 接收1个位的时钟周期计数
static u8 SUart_mRxBitCount; // 接收位计数
volatile u8 _SUart_mRxBuff;  // 接收缓存

volatile bit _SUart_mSending;
static u8 SUart_mTxStep;     // 发送步骤
static u8 SUart_mTxBuff;     // 发送缓存
static u8 SUart_mTxBitCount; // 发送位计数
static u8 SUart_mTxCycCount; // 发送1个位的时钟周期计数
#endif

#ifdef _SUART_USE_SYNC_MODE
u8 SUart_ReceiveByte()
{
    u8 _SUart_mRxBuff = 0;    // 接收缓存
    u8 SUart_mRxStep = _SUART_INIT_STATE;     // 接收步骤
#if (_SUART_WAIT_TICK <= 205)
    u8 SUart_mRxCycCount = 0; // 接收时钟周期计数, 接收超时计数
#else
    u16 SUart_mRxCycCount = 0;// 接收时钟周期计数, 接收超时计数
#endif
    u8 SUart_mRxBitCount = 0; // 接收位计数

    _SUart_EvStartReceive();
    while (1)
    {
        SUart_mRxCycCount++;
#if (_SUART_INIT_STATE == 0)
        if (SUart_mRxStep == 0) //// 等待高电平
        {
            if (_SUart_GetRxPin()) SUart_mRxStep++;   // SUart_mRxCycCount = 0;
    #if (_SUART_WAIT_TICK > 0) // 不死等
            else
            {
                if (SUart_mRxCycCount == 40 + _SUART_WAIT_TICK) 
                {
                    _SUart_EvReceiveError(SUart_mRxStep);  // 接收错误
                    break;
                }
            }
    #endif
        }
        else if (SUart_mRxStep == 1) //// 等待低电平（第一次检测到的低电平是起始位刚跳变时候）
        {
            if (!_SUart_GetRxPin()) SUart_mRxStep++;
    #if (_SUART_WAIT_TICK > 0) // 不死等
            else
            {
                if (SUart_mRxCycCount == 50 + _SUART_WAIT_TICK) 
                {
                    _SUart_EvReceiveError(SUart_mRxStep);  // 接收错误
                    break;     
                }
            }
    #endif
        }
#else
        if (SUart_mRxStep == 1) //// 等待低电平（第一次检测到的低电平是起始位刚跳变时候）
        {
            if (!_SUart_GetRxPin()) SUart_mRxStep++;
    #if (_SUART_WAIT_TICK > 0) // 不死等
            else
            {
                if (SUart_mRxCycCount == 10 + _SUART_WAIT_TICK)
                {
                    _SUart_EvReceiveError(SUart_mRxStep);  // 接收错误: 等待起始位超时
                    break;
                }
            }
    #endif
        }
#endif
        else if (SUart_mRxStep == 2) //// 接收起始位（低电平，这个时刻正常来说处于起始位的中间周期）
        {
            if (!_SUart_GetRxPin())
            {
                SUart_mRxStep++;
                SUart_mRxCycCount = 0;
            }
            else
            {
                _SUart_EvReceiveError(SUart_mRxStep);  // 接收错误：
                break; // 起始位错误 直接退出
            }
        }
        else if (SUart_mRxStep == 3) //// 接收数据
        {
            if (SUart_mRxCycCount == 3)
            {
                SUart_mRxCycCount = 0;
                _SUart_mRxBuff >>= 1;
                if (_SUart_GetRxPin())
                {
                    _SUart_mRxBuff |= 0x80;
                }
                SUart_mRxBitCount++;
                if (SUart_mRxBitCount == 8)
                {
                    SUart_mRxStep++;
                    //SUart_Event(SUART_EV_RX_DONE);
                }
            }
        }
        else //// 接收停止位（高电平）
        {
            if (_SUart_GetRxPin())
            {
                // 收到了停止位，重新等待低电平(这里有可能依然是最后一位高电平，下次接收会等待下降沿，所以无所谓)
                break;  // 接收完成
            }
            else if (SUart_mRxCycCount == 3)
            {
                _SUart_EvReceiveError(SUart_mRxStep);  // 接收错误
                break;   
            }
        }
        _SUart_Wait();  // 等待定时器时间到，同时开始计时下一个周期
    }
    _SUart_EvStopReceive();
    return _SUart_mRxBuff;
}


void SUart_SendByte(u8 SUart_mTxBuff)
{
    u8 SUart_mTxStep = 0;     // 发送步骤
    u8 SUart_mTxBitCount = 0; // 发送位计数
    u8 SUart_mTxCycCount = 0; // 发送1个位的时钟周期计数

    _SUart_EvStartSend();
#ifdef _SUART_HALF_DUPLEX
    _SUart_PinTxMode();
#endif
    while (1)
    {
        SUart_mTxCycCount++;
        if (SUart_mTxCycCount == 3)
        {
            SUart_mTxCycCount = 0;
            if (SUart_mTxStep == 0) // 发送起始位
            {
                _SUart_SetTxPin(0);
                SUart_mTxStep++;
            }
            else if (SUart_mTxStep == 1) // 发送数据
            {
                _SUart_SetTxPin(SUart_mTxBuff & 0x01);
                SUart_mTxBuff >>= 1;
                SUart_mTxBitCount++;
                if (SUart_mTxBitCount == 8)
                {
                    SUart_mTxStep++;
                }
            }
            else if (SUart_mTxStep == 2) // 发送结束位
            {
                _SUart_SetTxPin(1);
                SUart_mTxStep++;
            }
            else // 发送完毕
            {
                break;
            }
        }
        _SUart_Wait();
    }
#ifdef _SUART_HALF_DUPLEX
    _SUart_PinRxMode();
#endif
    _SUart_EvStopSend();
}
#else
// 声明引用事件通知函数（避免使用函数指针的妥协）
// 在你的应用代码中定义这个函数用于接收事件
void SUart_Event(suart_ev_t e);

void SUart_EvTimer()
{
    if (_SUart_Run)
    {
#ifdef _SUART_HALF_DUPLEX
        if (!_SUart_mSending)
#endif
        {
            if (SUart_mRxStep == 0) // 等待高电平
            {
                if (_SUart_GetRxPin())
                {
                    SUart_mRxStep++;
                }
            }
            else if (SUart_mRxStep == 1) // 等待低电平（第一次检测到的低电平是起始位刚跳变时候）
            {
                if (!_SUart_GetRxPin())
                {
                    SUart_mRxStep++;
                }
            }
            else if (SUart_mRxStep == 2) // 接收起始位（低电平，这个时刻正常来说处于起始位的中间周期）
            {
                if (!_SUart_GetRxPin())
                {
                    SUart_mRxStep++;
                    SUart_mRxCycCount = 0;
                    SUart_mRxBitCount = 0;
                }
                else
                {
                    SUart_mRxStep = 1; // 起始位错误，重新等待低电平
                }
            }
            else if (SUart_mRxStep == 3) // 接收数据
            {
                SUart_mRxCycCount++;
                if (SUart_mRxCycCount == 3)
                {
                    SUart_mRxCycCount = 0;
                    _SUart_mRxBuff >>= 1;
                    if (_SUart_GetRxPin())
                    {
                        _SUart_mRxBuff |= 0x80;
                    }
                    SUart_mRxBitCount++;
                    if (SUart_mRxBitCount == 8)
                    {
                        SUart_mRxStep++;
                        SUart_Event(SUART_EV_RX_DONE);
                    }
                }
            }
            else // 接收停止位（高电平）
            {
                SUart_mRxCycCount++;
                if (_SUart_GetRxPin())
                {
                    SUart_mRxStep = 1; // 收到了停止位，重新等待低电平(这里有可能依然是最后一位高电平，因为SUart_Event执行时间可能较长会影响停止位的接收，所以没有严格等待3个时钟周期。)
                }
                else if (SUart_mRxCycCount == 3)
                {
                    SUart_mRxStep = 0; // 停止位电平错误，重新等待高电平（如果SUart_Event处理时间大于3个时钟周期也会导致这个错误）
                    SUart_Event(SUART_EV_STOP_ERR);
                }
            }
        }
        if (_SUart_mSending)
        {
            SUart_mTxCycCount++;
            if (SUart_mTxCycCount == 3)
            {
                SUart_mTxCycCount = 0;
                if (SUart_mTxStep == 0) // 发送起始位
                {
                    _SUart_SetTxPin(0);
                    SUart_mTxStep++;;
                }
                else if (SUart_mTxStep == 1) // 发送数据
                {
                    _SUart_SetTxPin(SUart_mTxBuff & 0x01);
                    SUart_mTxBuff >>= 1;
                    SUart_mTxBitCount++;
                    if (SUart_mTxBitCount == 8)
                    {
                        SUart_mTxStep++;
                    }
                }
                else if (SUart_mTxStep == 2) // 发送结束位
                {
                    _SUart_SetTxPin(1);
                    SUart_mTxStep++;
                }
                else // 发送完毕
                {
                    _SUart_mSending = false;
#ifdef _SUART_USE_TX_DONE_EVENT
                    SUart_Event(SUART_EV_TX_DONE);
#endif
#ifdef _SUART_HALF_DUPLEX
                    _SUart_PinRxMode();
#endif
                }
            }
        }
    }
}

void SUart_SendByte(u8 one_byte)
{
#ifdef _SUART_HALF_DUPLEX
    _SUart_PinTxMode();
#endif
    SUart_mTxCycCount = 0;
    SUart_mTxBitCount = 0;
    SUart_mTxStep = 0;
    SUart_mTxBuff = one_byte;
    _SUart_mSending = true;
}

#endif
